classdef Signal < MeasurementComponent.Signal.AbstractSignal
    %SIGNAL Summary of this class goes here
    %   Detailed explanation goes here
    
    properties(Access = private)
        liaChannel
        reference
    end
    
    methods
        function obj = Signal(name, liaChannel, varargin)
            %SIGNAL Construct an instance of this class
            %   Detailed explanation goes here
            p=inputParser;
            p.addRequired('name', @ischar);
            p.addParameter('reference', [], @(x) isempty(x) || isa(x, 'MeasurementComponent.Actuator.AbstractActuator'));
            p.parse(name, varargin{:});
            
            obj@MeasurementComponent.Signal.AbstractSignal(name);
            obj.liaChannel = liaChannel;
            obj.reference = p.Results.reference;
            if ~isempty(p.Results.reference)
                obj.referencedBy(p.Results.reference);
            end
        end
        function lia = getLIAchannel(obj)
            lia = obj.liaChannel;
        end
        function disp(obj)
            disp(obj.liaChannel);
        end
    end
    %%
    methods
        function obj = subscribe_signal(obj, signal, varargin)
            p=inputParser;
            p.addRequired('signal', @(x) isa(x, 'ziStreamSignal'));
            p.addOptional('group', [1, 1, 1], @(x) isnumeric(x) && length(x) == 3 && x(3)<=x(1)*x(2));
            p.parse(signal, varargin{:});
            subscribe_signal@MeasurementComponent.Signal.AbstractSignal(obj, obj, signal, varargin{:});
        end
        
        function obj = reset(obj)
            obj.liaChannel.initialize();
        end
        
        function obj = setupLIAchannel(obj, varargin)
            obj.liaChannel.setup(varargin{:});
        end
        
        function res = getSetting(obj, setting)
            try
                res = obj.liaChannel.current_setting.(setting);
            catch
                error('Setting [%s] is not returned correctly.', setting);
            end
        end
        
        function obj = referencedBy(obj, actuator)
            p=inputParser;
            p.addRequired('actuator', @(x) isa(x, 'MeasurementComponent.Actuator.AbstractActuator'));
            [oscIndex, freq] = actuator.port.driver.getOscillator();
            obj.setupLIAchannel('extRefStatus',   false, ...
                                'extRefAutoMode', -1, ...
                                'oscSelect', oscIndex, ...
                                'oscFrequency', freq);
        end
        
        function phase = autoZeroPhase(obj)
            phase = obj.liaChannel.autoZeroPhase();
        end
        
        function obj = export_to_AuxOut(obj, index, signal, varargin)
            p=inputParser;
            p.addRequired('index', @Miscellaneous.isZIindex4);
            p.addRequired('signal', @(x) isa(x,  'ziAuxOutSignal'));
            p.addParameter('preoffset', 0.0, @isnumeric);
            p.addParameter('scale',     0.0, @isnumeric);
            p.addParameter('offset',     0.0, @isnumeric);
            p.addParameter('limitlower',  -10, @(x) x>=-10 && x<=10);
            p.addParameter('limitupper',   10, @(x) x>=-10 && x<=10);
            p.parse(index, signal, varargin{:});
            
            zi = obj.liaChannel.device;
            port = zi.AuxOutPort(index);
            port.setup(varargin{:}, 'outputSelect', p.Results.signal, 'demodSelect', obj.liaChannel.index);
        end
        
        function obj = diableAuxOutput(obj, index)
            zi = obj.liaChannel.device;
            port = zi.AuxOutPort(index);
            port.setManual(0);
        end
    end
end

